export function convertLetterToNumber(str) {
  var out = 0, len = str.length;
  for (let pos = 0; pos < len; pos++) {
    out += (str.charCodeAt(pos) - 64) * Math.pow(26, len - pos - 1);
  }
  return out;
}

export function toLetters(num) {
  "use strict";
  var mod = num % 26,
    pow = num / 26 | 0,
    out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
  return pow ? toLetters(pow) + out : out;
}

export function parseKey(key = '') {
  let row = key.match(/\d+/g)[0]
  let columnIndex = convertLetterToNumber(key.replace(row, ''))
  let rowIndex = parseInt(row)
  return {
    r: rowIndex - 1,
    c: columnIndex - 1
  }
}



export function useDataGrid({url, opt = {}, ...options} = {}) {

  let state = ZY.T.state({
    loaded: false,
    result: []
  })

  async function req() {
    let lodash = ZY.lodash;
    let [err, res] = await ZY.awaitTo(window.Req.get(url, opt));
    if (err) {
      return Promise.reject(err)
    }
    state.loaded = true
    res.result.defs = res.result.defs.map(v => {
      v.origin_id = v.id
      v.id = ZY.rid(6);
      return v
    })
    res.result.originStr = res.result.origin
    res.result.origin = ZY.JSON5.parse(res.result.origin)[0]


    res.result.defs = res.result.defs.filter(v => {
      if (v.formServer) {
        return true
      }
      if (!v.config) {
        return false
      }

      if (!v.config.fieldName && !v.config.tableName) {
        return false
      }
      return true
    })
    // console.log( res.result.defs)

    if (options && options.onReady) {
      options.onReady(res)
    }

    let merge = lodash.get(res.result.origin, 'config.merge', {})
    // console.log('merge', merge)
    lodash.each(merge, function (item, key) {
      // console.log(item, key)
      item.re = item.r + item.rs
      item.ce = item.c + item.cs
      item.cells = []
    })
    let mergeArr = Object.entries(merge)
    // console.log(mergeArr)


    let celldata = lodash.get(res.result.origin, 'celldata', [])
    lodash.each(celldata, function (cell) {
      // console.log(cell)
      let letter = toLetters(cell.c + 1) + (cell.r + 1)
      // let merge_key = cell.r + '_' + cell.c

      for (let [row, c] of mergeArr) {
        if (cell.r >= c.r && cell.r < c.re) {
          if (cell.c >= c.c && cell.c < c.ce) {
            if (!c.config) {
              c.config = cell
            }
            c.cells.push(cell)
            return;
          }
        }
      }


      let o = {
        id: ZY.rid(6),
        range: letter + ':' + letter,
        content: cell.v.m,
        formServer: true,
        cell: cell,
      }
      res.result.defs.push(o)
    })

    for (let [row, cell] of mergeArr) {
      // console.log(cell)
      let letter1 = toLetters(cell.c + 1) + (cell.r + 1)
      let letter2 = toLetters(cell.ce) + (cell.re)
      let range = letter1 + ':' + letter2
      let o = {
        id: ZY.rid(6),
        range: letter1 + ':' + letter2,
        rangeArr: [
          letter1,
          letter2
        ],
        content: cell.config.v.m,
        formServer: true,
        cell: cell.config,
        isMerge: true
      }
      if (!o?.cell?.v?.bg) {
        o.cell.v.bg = options?.bg ?? '#fff'
      }
      let finded = res.result.defs.find(v => {
        let flag = false
        if (v.range === range) {
          flag = true
        } else {
          let v_rangeArr = v.range.split(':')
          if (Array.isArray(v_rangeArr)) {
            v_rangeArr.forEach(item => {
              if (o.rangeArr.includes(item)) {
                flag = true
              }
            })
          }
        }
        return flag
      })
      // console.log(finded)
      if (finded) {
        finded.cell = cell.config

        finded.range = o.range
      } else {
        res.result.defs.push(o)
      }
    }

    res.result.model = {}

    res.result.mergeMap = {}

    function resolveDefPOS(def) {
      def.srangeArr = def.range.split(':')
      if (def.srangeArr[0] === def.srangeArr[1]) {
        def.isSingle = true
        def.letterSingle = def.srangeArr[0]
      } else {
        res.result.mergeMap[def.srangeArr[0]] = {
          end: def.srangeArr[1]
        }
      }
      def.rangePos =  def.srangeArr.map(key => {
        let obj = parseKey(key);
        if (obj) {
          if (obj.r > lastRow) {
            lastRow = obj.r
          }
          if (obj.c > lastColumn) {
            lastColumn = obj.c
          }
        }
        return obj
      })
      def.cArr = def.rangePos.map(v => v.c).sort(function (a, b) {
        return a - b;
      });
      def.rArr = def.rangePos.map(v => v.r).sort(function (a, b) {
        return a - b;
      });
      if ( def.isSingle ) {
        def.rangePosCell = def.rangePos[0]
      }
    }


    let lastRow = 0;
    let lastColumn = 0;
    lodash.forEach(res.result.defs, function (def){
      let defVal = lodash.get(def, 'config.ui.defVal', undefined)
      if (def?.config?.fieldName && typeof defVal !== 'undefined') {
        res.result.model[def.config.fieldName] = defVal
      }
      resolveDefPOS(def)
      if (def?.config?.ui?.dataSourceType) {
        def.config.ui.enableRemote = true
      }
    })
    // lodash.forEach( res.result.selectDefs, function (def) {
    //   resolveDefPOS(def)
    // })
    // console.log(lastRow, lastColumn)
    res.result.lastRow = lastRow
    res.result.lastColumn = lastColumn
    state.result = res.result;

    // console.timeEnd('111')

    window.__last_grid_result__ = res.result
  }

  req()

  function getExt() {
    let treeList = ZY.lodash.get(state.result, 'treeList', [])
    let formName = ZY.lodash.get(opt, 'params.formName', '');
    let finded = null
    if (formName) {
      finded = treeList.find(v => v.formName === formName)
    }
    return finded
  }


  async function submit(formCtx) {
    let ext = getExt()
    let [isValid, errors, data] = await formCtx.submit()
    let business = []
    Object.entries(data).forEach(([key, value]) => {
      let def = state.result.defs.find(v => {
        let fieldName = v?.config?.fieldName
        return fieldName === key
      })
      if (def) {
        business.push({
          ...def?.config,
          fieldValue: value
        })
      }
    })
    let obj = {
      business,
      ...ext
    }
    return {
      ext, isValid, errors, data, obj
    }
  }

  function getResult() {
    return state.result ?? {}
  }

  function mergeArr(arr = []) {
    let a = [];
    let map = state.result.mergeMap ?? {}
    arr.forEach(item => {
      if (map.hasOwnProperty(item.key)) {
        a.push(
          map[item.key].end
        )
      }
    })
    return  arr.concat(a)
  }

  function getAllCells() {
    let arr = [];
    state.result.defs.forEach(v => {
      if (v.rangeArr[0] === v.rangeArr[1]) {
        arr = arr.concat(v.rangeArr);
      } else {
        // console.log('sdsds', v.rangePos)


        let _a = []
        let [p1, p2] = v.rangePos;

        for (let c1 = p1.c; c1 <= p2.c; c1++) {
          for (let r1 = p1.r; r1 <= p2.r; r1++) {
            let key = toLetters(c1 + 1) + (r1 + 1);
            // console.log(key)
            _a.push(key)
          }
        }
        arr = arr.concat(_a);
      }
    })
    let a = [...new Set(arr)]
    // console.log(a)
    return a;
  }

  return {
    getAllCells,
    state,
    submit,
    mergeArr,
    getResult,
    getExt,
    req
  }
}

export function useGridBatchSelect(props, ctx, {idKey = 'id', getAppScrollY = null} = {}) {
  const {watch, nextTick, reactive} = window.vueCompositionAPI
  let state = reactive({
    selectIdxs: []
  })


  let id = ZY.rid()
  let selector = '.el-table__body-wrapper .el-table__row'
  let relSelector = ''
  let singleData = null
  let uniqueIds = []
  let isProgram = false
  let isNeedWatch = true

  function tableRowClassName({row, rowIndex}) {
    // console.log('row', row, rowIndex)
    if (!Array.isArray(uniqueIds)) {
      return ''
    }
    let ids = uniqueIds.map(v => v.dataset.uuid)
    // console.log(ids)
    if (ids.includes(row[idKey])) {
      return 'batch-row--selected'
    }
    // if (rowIndex === 1) {
    //   return 'warning-row';
    // } else if (rowIndex === 3) {
    //   return 'success-row';
    // }
    return '';
  }

  function tableRowClick(row, column, e) {
    // console.log('row, column, event', isProgram, row, column, event)
    //
    // isProgram = true
    // uniqueIds = []
    if (e.ctrlKey) {
      isNeedWatch = false
      // console.log(uniqueIds)
      uniqueIds.push({
        dataset: {
          uuid: row[idKey]
        }
      })
      uniqueIds = ZY.lodash.uniqBy(uniqueIds, 'dataset.uuid')
      singleData = null
      nextTick(() => {
        isNeedWatch = true
      })
      return
    }
    if (!isProgram) {
      isNeedWatch = false
      // state.selectIdxs.splice(0)
      uniqueIds = [{
        dataset: {
          uuid: row[idKey]
        }
      }]
      // singleData = {row}
      singleData = null
      nextTick(() => {
        isNeedWatch = true
      })
    }
  }

  function getSelectedUUIDS() {
    if (uniqueIds.length < 1 && singleData) {
      return [singleData.row[idKey]]
    }
    // console.log(singleData)
    return uniqueIds.map(v => v.dataset.uuid)
  }

  function getSelectedContents() {
    // console.log(singleData)
    if (uniqueIds.length < 1 && singleData) {
      return [singleData.row]
    }
    return uniqueIds.map(v => {
      if (v.content) {
        return ZY.JSON5.parse(v.content)
      }
      return undefined
    })
  }

  function cancelSelect() {
    isProgram = true
    isNeedWatch = false
    state.selectIdxs.splice(0)
    uniqueIds = []
    singleData = null
    document.querySelector(selector).click()
    let elTableCtx = ctx.refs.zTable.$_getTable()
    // console.log(document.querySelector('.el-table__body-wrapper'))
    // ctx.refs.table.$refs.table.setCurrentRow()
    elTableCtx?.setCurrentRow()
    nextTick(() => {
      isNeedWatch = true
      isProgram = false
    })
  }

  function getScrollY() {
    if (getAppScrollY) {
      return getAppScrollY()
    }
    return 0;
  }

  let tool = {
    state,
    id,
    selector,
    getScrollY,
    tableRowClassName,
    relSelector,
    cancelSelect,
    getSelectedUUIDS,
    getSelectedContents,
    tableRowClick
  }

  watch(() => state.selectIdxs, function (newVal, oldVal) {
    // console.log(newVal, oldVal, isNeedWatch)
    if (isNeedWatch) {
      uniqueIds = ZY.lodash.uniqBy(state.selectIdxs, 'dataset.uuid');
      singleData = null
      // console.log(uniqueIds)
      // console.log(    ctx.refs.table.$refs.table)
      // ctx.refs.table.$refs.table.doLayout()
      nextTick(() => {
        isProgram = true
        document.querySelector(selector).click()
        // console.log(ctx.refs.searchTable.getElTable())
        let elTableCtx = ctx.refs.zTable.$_getTable()
        // console.log(document.querySelector('.el-table__body-wrapper'))
        // ctx.refs.table.$refs.table.setCurrentRow()
        elTableCtx?.setCurrentRow()
        nextTick(() => {
          isProgram = false
        })
      })
    }
  })
  return tool
}

export function useArrTool(keys = [], current = '') {
  let arrTool = {}
  arrTool.state = ZY.T.state({
    current: current,
    keys: keys
  })

  function checkLastCurrent(v) {

    if (arrTool.state.current === v) {
      arrTool.state.current = ZY.lodash.nth(arrTool.state.keys, -1);
    }
  }

  arrTool.append = function (v) {
    arrTool.state.keys.push(v)
    if (!arrTool.state.current) {
      arrTool.state.current = v
    }
  }

  function rm(v, args) {
    // console.log(args)
    arrTool.state.keys.splice(...args);
    checkLastCurrent(v)
  }

  arrTool.delByValye = function (v, len = 1) {
    let index = arrTool.state.keys.findIndex(a => a === v)
    if (index > -1) {
      // console.log('delByValye', v, index)
      arrTool.state.keys.splice(index, len);
      // let nIndex = index - 1
      // if (nIndex > -1) {
      //   arrTool.state.current = arrTool.state.keys[nIndex]
      // }
      if (arrTool.state.current === v) {
        arrTool.state.current = arrTool.state.keys[index - 1]
      }
    }
  }
  arrTool.remove = function (...args) {
    let v = ZY.lodash.nth(arrTool.state.keys, args[0]);
    // console.log(arrTool.state.current, v)
    rm(v, args)
  }
  arrTool.handleChange = function (e) {
    // console.log('handleChange', e.target.selected)
    arrTool.state.current = e.target.selected
  }
  return arrTool
}

export function useFetchDataSource() {
  let cachedData = []

  function initReq(apiConfig, {token = ''} = {}) {
    let {config = {}, ui, url} = apiConfig
    let reqOption = {
      method: 'get',
      url: url
    }
    if (ui.dataSourceType === '参数') {
      if (Array.isArray(ui.customParamObject)) {
        cachedData = ui.customParamObject.map(v => {
          v._value = v.value
          if (!v.hasOwnProperty('label')) {
            v.label = v.key
          }
          // if (!v.hasOwnProperty('value')) {
          //   v.value = v.value
          // }
          return v
        })
      }
    }

    if (ui.dataSourceType === '接口') {
      reqOption.url = ui.interfacePath
      reqOption.method = ui.interfaceMethods
    }

    if (ui.dataSourceType === '字典') {
      reqOption.url = `/zy-boot/form/getDictItem?id=${ui.dataSource}`
    }

    let ajaxOption = {
      headers: {
        ['X-Access-Token']: token,
        // ['X-Random']: ZY.rid()
      }
    }

    return [reqOption, ajaxOption];
  }

  function getRes(res = {}) {
    let ret = []
    if (res?.result?.options) {
      ret = res.result?.options ?? []
    } else if (res?.result) {
      ret = res.result
    }
    return ret
  }

  async function req({reqOption, ajaxOption} = {}) {
    if (Array.isArray(cachedData) && cachedData.length > 0) {
      return cachedData
    }
    if (reqOption.url) {
      let r = ZY.rid()
      if (reqOption.url.includes('?')) {
        r = reqOption.url + '&v=' + r
      } else {
        r = reqOption.url + '?v=' + r
      }

      if (reqOption.method === 'get') {
        let [err, res] = await ZY.awaitTo(window.Req.get(r, ajaxOption))
        // console.log(cachedData, reqOption, res)
        return getRes(res)
      }

      if (reqOption.method === 'post') {
        let [err, res] = await ZY.awaitTo(window.Req.post(r, {}, ajaxOption))
        return getRes(res)
      }
    }
  }

  return {
    req,
    initReq,
    getRes
  }
}

export let SortByIndex = {
  sortArr(_arr = [], obj_path = 'ui.area') {
    let arr = []
    arr = _arr.sort(function (a, b) {
      let area1 = ZY.lodash.get(a, obj_path, '');
      let area2 = ZY.lodash.get(b, obj_path, '');
      // console.log(area1, area2)

      if (!area1 || !area2) {
        return 0
      }

      const isNumber = (v) => (+v).toString() === v;
      const aPart = area1.match(/\d+|\D+/g);
      const bPart = area2.match(/\d+|\D+/g);
      let i = 0;
      let len = Math.min(aPart.length, bPart.length);
      while (i < len && aPart[i] === bPart[i]) {
        i++;
      }
      if (i === len) {
        return aPart.length - bPart.length;
      }
      if (isNumber(aPart[i]) && isNumber(bPart[i])) {
        return aPart[i] - bPart[i];
      }
      return aPart[i].localeCompare(bPart[i]);
      // return 0
    })
    // console.log('sort', arr)
    return arr
  },

  sort(p = {}, obj_path = 'ui.area') {
    let arr = []
    arr = Object.entries(p.properties).sort(function (a, b) {
      let area1 = ZY.lodash.get(a[1], obj_path, '');
      let area2 = ZY.lodash.get(b[1], obj_path, '');
      // console.log(area1, area2)

      if (!area1 || !area2) {
        return 0
      }

      const isNumber = (v) => (+v).toString() === v;
      const aPart = area1.match(/\d+|\D+/g);
      const bPart = area2.match(/\d+|\D+/g);
      let i = 0;
      let len = Math.min(aPart.length, bPart.length);
      while (i < len && aPart[i] === bPart[i]) {
        i++;
      }
      if (i === len) {
        return aPart.length - bPart.length;
      }
      if (isNumber(aPart[i]) && isNumber(bPart[i])) {
        return aPart[i] - bPart[i];
      }
      return aPart[i].localeCompare(bPart[i]);
      // return 0
    })
    // console.log('sort', arr)
    p.properties = Object.fromEntries(arr)
  },


  deepSort(p) {
    ZY.lodash.each(p.properties, function (item, key) {
      if (item.type === 'object') {
        SortByIndex.sort(item)
      } else if (item.type === 'array') {
        // console.log('deepSort', item)
        SortByIndex.sort(item.items)
      }
    })
  }
}

/**
 * 创建简单form创建起
 * @returns {{init: ((function(*=): Promise<void>)|*), state, properties: {}}}
 */
export function createEasyForm({handleProperties, request = window.Req} = {}) {

  let formCtx = {}

  let state = ZY.T.state({
    style: {},
    loading: false,
    inited: false
  })
  let properties = {}
  // if (!urlMap) {
  //   urlMap = {
  //     add: url,
  //     edit: url
  //   }
  // }
  let option = {}


  async function init(apiAddress = '', {autoLoad = true} = {}) {
    if (!apiAddress) {
      return;
    }
    let [err, res] = await ZY.awaitTo(request.get(apiAddress));
    let obj = {
      properties: res.result
    }
    // SortByIndex.sort(obj)
    // SortByIndex.deepSort(obj)
    let r = obj.properties
    // console.log(Object.keys(r))

    if (handleProperties) {
      r = handleProperties(r)
    }
    tool.properties = r
    await ZY.sleep(300);
    state.inited = true;
    option.autoLoad = autoLoad
  }

  async function onSubmit(model, scope = {}) {
    // console.log('onSubmit', model, scope)
    if (option.autoSubmit) {
      let method = request.post;
      let reqUrl = option.url
      let sms = {
        data: model
      }
      if (scope?.IS_EDIT) {
        method = request.put;
        reqUrl = option.editUrl;
      }
      let [err, res] = await ZY.awaitTo(method(reqUrl, sms, {
      }));
      if (!err) {
        if (tool.onSubmitSuccess) {
          tool.onSubmitSuccess(res);
        }
      }
    }
  }

  function setOption(v) {
    option = v
  }

  async function load(url) {
    if (url) {
      state.loading = true
      let [err, res] = await ZY.awaitTo(request.get(url, {
      }, {
      }))

      state.loading = false
      if (err) {
        return;
      }
      if (formCtx.form) {
        formCtx.form.importData(res?.result.data)
      }
    }
  }

  async function onReady(e) {
    // console.log('onReady', option)
    formCtx = e
    if (option.autoLoad) {
      load(option.detailUrl)
    }
    if (tool.onFormReady) {
      tool.onFormReady()
    }
  }

  let tool = {
    state,
    onReady,
    onSubmit,
    setOption,
    load,
    properties,
    init
  }

  return tool
}
